/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package com.pearreview.util.review.io;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.pearreview.util.review.Aspect;
import com.pearreview.util.review.Catalog;
import com.pearreview.util.review.IdLinkedList;
import com.pearreview.util.review.IdList;

public class XMLCatalogReader implements CatalogReader {

	private static final long serialVersionUID = 5187801736297027769L;
	
	public XMLCatalogReader() {
		super();
	}

	@Override
	public Catalog read(File file) throws SAXException, IOException, 
			URISyntaxException, NotValidXMLException, 
			ParserConfigurationException {
		XMLSchemaValidator validator = new XMLSchemaValidator();
		
		//throw an exception if file is not valid
		if (!validator.validate(file)) {
			throw new NotValidXMLException(validator.getLastErrorMessage());
		}

		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setIgnoringComments(true);
		factory.setNamespaceAware(false);
		DocumentBuilder loader = factory.newDocumentBuilder();

		Document document = loader.parse(file);
		Element root = document.getDocumentElement();
		
		Catalog catalog = null;
		
		if(root.getNodeName().endsWith("catalog")) {
			catalog = readCatalog(root);
		} else if(root.getNodeName().endsWith("review")) {
			catalog = readReview(root);
		}
		
		return catalog;
	}
	
	private Catalog readCatalog(Node catalogRoot) {
		Catalog catalog = new Catalog();
		
		NodeList nodes = catalogRoot.getChildNodes();
		
		for( int i = 0 ; i < nodes.getLength() ; i++ ) {
			Node node = nodes.item(i);
			
			if(node.getNodeName().endsWith("description")) {
				catalog.setDescription(node.getTextContent());
			} else if(node.getNodeName().endsWith("aspects")) {
				catalog.setAspects(readAspects(node));
			}
		}
		
		return catalog;
	}
	
	private Catalog readReview(Node reviewRoot) {
		Catalog catalog = new Catalog();
		
		catalog.setAspects(readAspects(reviewRoot));
		
		return catalog;
	}
	
	private IdList<Aspect> readAspects(Node aspectsRoot) {
		IdList<Aspect> aspects = new IdLinkedList<Aspect>();
		
		NodeList nodes = aspectsRoot.getChildNodes();
		
		for( int i = 0 ; i < nodes.getLength() ; i++ ) {
			Node node = nodes.item(i);
			
			 if(node.getNodeName().endsWith("aspect")) {
				aspects.add(readAspect(node));
			 }
		}		
		
		return aspects;
	}
	
	private Aspect readAspect(Node aspectRoot) {
		Aspect aspect = new Aspect();
		
		NodeList nodes = aspectRoot.getChildNodes();
		
		for( int i = 0 ; i < nodes.getLength() ; i++ ) {
			Node node = nodes.item(i);
			
			if(node.getNodeName().endsWith("id")) {
				aspect.setId((node.getTextContent()));
			} else if(node.getNodeName().endsWith("category")) {
				aspect.setCategory((node.getTextContent()));
			} else if(node.getNodeName().endsWith("directive")) {
				aspect.setDirective((node.getTextContent()));
			} else if(node.getNodeName().endsWith("description")) {
				aspect.setDescription((node.getTextContent()));
			}
		}		
		
		return aspect;
	}
}
